package demo.security;

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

	@Configuration
	@EnableWebSecurity
	static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

		@Bean
		@Override
		public UserDetailsService userDetailsService() {
			return new UserDetailsService() {
				@Override
				public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
					String[] roles;
					if (username.startsWith("user")) {
						roles = new String[] { "USER" };
					} else if (username.startsWith("admin")) {
						roles = new String[] { "USER", "ADMIN" };
					} else {
						roles = new String[] { username.toUpperCase() };
					}
					return User.withDefaultPasswordEncoder().username(username).password(username).roles(roles).build();
				}
			};
		}

		@Override
		@Bean
		public AuthenticationManager authenticationManagerBean() throws Exception {
			return super.authenticationManagerBean();
		}

		@Override
		protected void configure(HttpSecurity http) throws Exception {
						
			//@formatter:off
			http.requestMatchers()
					.antMatchers("/login", "/oauth/authorize")
					.and()
				.authorizeRequests().anyRequest().authenticated()
					.and()
				.formLogin().permitAll();
			//@formatter:on
		}
	}

	// @formatter:off
	@Override
	public void configure(HttpSecurity http) throws Exception {
		log.debug("***ResourceServerConfiguration:configure(HttpSecurity http): {}", http);
		
		http.requestMatcher(new RequestMatcher() {
			@Override
			public boolean matches(HttpServletRequest request) {
				boolean isMatched = false;

				String authorization = request.getHeader("Authorization");
				if (authorization != null && (authorization.startsWith(OAuth2AccessToken.BEARER_TYPE)
						|| authorization.startsWith("Basic"))) {
					isMatched = true;
					log.debug("*****requestURI[{}], Authorization[{}]", request.getRequestURI(), authorization);	
				}
				// check if access token exists
				String accessToken = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN);
				if (accessToken != null) {
					isMatched = true;
					log.debug("*****requestURI[{}], Access_token[{}]", request.getRequestURI(), accessToken);
				}

//				log.debug(
//						"*****ResourceServerConfiguration RequestMatcher: isMatched:{}, authorization:{}, accessToken:{}, requestURI:{}",
//						isMatched, authorization, accessToken, request.getRequestURI());

				return isMatched;
			}
		}).authorizeRequests().anyRequest().authenticated();
	}
	// @formatter:on
}
